package com.clas.liu.myapplication.presenter.impl;

import android.os.Handler;
import android.os.Message;

import com.clas.liu.myapplication.model.i.IBaseModel;
import com.clas.liu.myapplication.model.impl.BaseModel;
import com.clas.liu.myapplication.view.activity.i.IBaseActivity;
import com.clas.liu.myapplication.view.activity.impl.BaseActivity;

import java.lang.ref.WeakReference;

/**
 * presenter的基类
 * Created by liu on 2019/2/27.
 */

public abstract class BasePresenter <V extends BaseActivity & IBaseActivity,
        M extends BaseModel & IBaseModel> {

    V mView;
    M mModel;

    public BasePresenter(V view) {
        this.mView = view;
        this.mModel = getModel(getHandler());
    }

    protected abstract M getModel(Handler handler);


    public Handler getHandler() {
        return new MainHandler(this);
    }

    /**
     * **
     * 这个方法处理网络请求成功后从model层发送过来的事件
     * 子类在复写此方法时,从msg获取的obj请转换为对应的model中发送的类型
     * 在对应的Activity销毁后在调用这个方法会抛出NullPointerException,在调用这个方法的位置catch异常!!!
     * 异常发生原因:这个方法会使用持有的activity来调用activity的方法,当activity销毁后再调用activity的方法就
     * 会发生异常.将异常从这个函数抛出,在调用这个函数的地方catch.至于为什么不在异常发生的时候就catch,原因如下:
     * 1.如果要在发生的时候就catch需要在每个子类写try-catch代码块,比较繁琐;
     * 2.这个方法最主要的功能就是调用activity的方法,当activity销毁后这个方法就没有继续执行的意义,所以直接从
     * 这个方法抛出异常,没有必要再执行这个方法抛出异常之后的代码
     *
     * @param msg 消息,mes.what用于区分是哪个网络请求返回了,msg.obj包含了网络请求返回的数据
     */

    protected abstract void eventReceive(Message msg);

    public void onDestroy(){
        mView = null;
        if (mModel!=null){
            mModel.onDestroy();
            mModel = null;
        }
    }
    /**
     *  
     * 用于获取主线程的handler
     * 这个内部类必须是静态的,不能让这个类持有外部类的引用,否则可能会造成内存泄漏
     * 使用弱引用来关联外部类,当只有弱应用存在时，变量会被回收，所以,请注意空指针!!!
     *
     * @see #eventReceive(Message) 调用的这个方法可能会抛出NullPointerException,在这里处理掉,不要让没有
     * 必要的异常使程序崩溃
     */
    private static class MainHandler extends Handler{
        private WeakReference<BasePresenter> presenter;
        MainHandler(BasePresenter presenter){
            this.presenter = new WeakReference<BasePresenter>(presenter);
        }

        @Override
        public void handleMessage(Message msg) {
            if(presenter.get()!=null){
                try{
                    if(!presenter.get().mView.isFinishing())
                        presenter.get().eventReceive(msg);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            super.handleMessage(msg);
        }
    }

}
